package org.tinylog.impl.path;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Clock;
import java.time.ZoneId;
import java.time.ZonedDateTime;

import org.tinylog.core.internal.LoggingContext;
import org.tinylog.impl.path.segments.PathSegment;

/**
 * Dynamic file path with static and dynamic path segments.
 */
public class DynamicPath {

    private final Clock clock;
    private final ZoneId zone;
    private final PathSegment[] pathSegments;

    /**
     * @param context The current logging context
     * @param path The file path with placeholders
     */
    public DynamicPath(LoggingContext context, String path) {
        this.clock = context.getFramework().getClock();
        this.zone = context.getConfiguration().getZone();
        this.pathSegments = new PathParser(context).parse(path).toArray(new PathSegment[0]);
    }

    /**
     * Gets the latest existing path by resolving all static and dynamic path segments.
     *
     * @return The latest existing path or {@code null} if none exist
     * @throws Exception Failed to resolve the latest path
     */
    public Path getLatestPath() throws Exception {
        Path parentDirectory = Paths.get("");
        String prefix = "";

        for (int i = 0; i < pathSegments.length; ++i) {
            if (!Files.exists(parentDirectory)) {
                return null;
            }

            String result = pathSegments[i].findLatest(parentDirectory, prefix);
            if (result == null) {
                return null;
            }

            Path path = parentDirectory.resolve(prefix + result);
            if (i == pathSegments.length - 1) {
                return Files.isRegularFile(path) ? path : null;
            }

            String normalizedResult = path.normalize().toString();
            String separator = parentDirectory.getFileSystem().getSeparator();
            int separatorIndex = normalizedResult.lastIndexOf(separator);
            if (separatorIndex >= 0) {
                parentDirectory = Paths.get(normalizedResult.substring(0, separatorIndex));
                prefix = normalizedResult.substring(separatorIndex + 1);
            } else {
                parentDirectory = Paths.get(normalizedResult);
                prefix = "";
            }
        }

        return null;
    }

    /**
     * Generates a new file path by resolving all static and dynamic path segments.
     *
     * @return New static path
     * @throws Exception Failed to generate the file path
     */
    public Path generateNewPath() throws Exception {
        ZonedDateTime date = ZonedDateTime.ofInstant(clock.instant(), zone);
        StringBuilder builder = new StringBuilder();

        for (PathSegment segment : pathSegments) {
            segment.resolve(builder, date);
        }

        Path path = Paths.get(builder.toString()).toAbsolutePath();
        Path parent = path.getParent();
        if (parent != null) {
            Files.createDirectories(parent);
        }

        return path;
    }

}
